package com.pillar.game;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pillar.enty.Hall;
import com.pillar.handler.IHandler;
import com.pillar.request.BasePackage;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;

import static io.netty.handler.codec.http.HttpUtil.isKeepAlive;


@ChannelHandler.Sharable
@Slf4j
public class BizHandler extends ChannelInboundHandlerAdapter {

    public final static Hall hall = new Hall();

    private final IHandler[] mHandler;

    private WebSocketServerHandshaker handshaker;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public BizHandler(IHandler[] iHandler) {
       this.mHandler = iHandler;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
       try {
           if (msg instanceof FullHttpRequest) {
               //以http请求形式接入，但是走的是websocket
               handleHttpRequest(ctx, (FullHttpRequest) msg);
           } else if (msg instanceof WebSocketFrame) {
               //处理websocket客户端的消息
               handlerWebSocketFrame(ctx, (WebSocketFrame) msg);
           }
       }finally {
           ReferenceCountUtil.release(msg);
       }
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        //添加连接
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        //断开连接
        log.info("客户端断开连接：" + ctx.channel());
        NodeStatus.removeChannel(ctx.channel());
    }

    private void handlerWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
        // 判断是否关闭链路的指令
        if (frame instanceof CloseWebSocketFrame) {
            log.info("客户端下线");
            handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain());
            return;
        }
        // 判断是否ping消息
        if (frame instanceof PingWebSocketFrame) {
            log.info("ping:");
            ctx.channel().write(
                    new PongWebSocketFrame(frame.content().retain()));
            return;
        }
        // 本例程仅支持文本消息，不支持二进制消息
        if (!(frame instanceof TextWebSocketFrame)) {
            log.info("本例程仅支持文本消息，不支持二进制消息");
            throw new UnsupportedOperationException(String.format(
                    "%s frame types not supported", frame.getClass().getName()));
        }
        // 返回应答消息
        String request = ((TextWebSocketFrame) frame).text();

        try {
            boolean checkPassed = checkMessage(request);
            if (!checkPassed){
                ctx.close();
                log.error("报文校验失败");
                return;
            }
            dispatcherMessage(ctx.channel(),request);
        } catch (JsonProcessingException e) {
            ctx.close();
            log.error("报文解析失败{}",e);
        }

    }

    private void dispatcherMessage(Channel channel ,String request) throws JsonProcessingException {
        BasePackage basePackage = objectMapper.readValue(request, BasePackage.class);
        boolean apply;
        for (IHandler handler : mHandler){
            try {
                if (handler.apply(basePackage)){
                    apply = handler.consume(channel,basePackage);
                    if (!apply){
                        break;
                    }
                }
            }catch (Exception e){
                log.error("handler exception={}",request);
            }
        }
    }

    /**
     * 校验报文
     * @param request
     * @return
     */
    private boolean checkMessage(String request) {
        return true;
    }

    /**
     * 唯一的一次http请求，用于创建websocket
     */
    private void handleHttpRequest(ChannelHandlerContext ctx,
                                   FullHttpRequest req) {
        //要求Upgrade为websocket，过滤掉get/Post
        if (!req.decoderResult().isSuccess()
                || (!"websocket".equals(req.headers().get("Upgrade")))) {
            //若不是websocket方式，则创建BAD_REQUEST的req，返回给客户端
            sendHttpResponse(ctx, req, new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
            return;
        }
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                "ws://localhost:9999/websocket", null, false);
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory
                    .sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handshaker.handshake(ctx.channel(), req);
        }
    }

    /**
     * 拒绝不合法的请求，并返回错误信息
     */
    private static void sendHttpResponse(ChannelHandlerContext ctx,
                                         FullHttpRequest req, DefaultFullHttpResponse res) {
        // 返回应答给客户端
        if (res.status().code() != 200) {
            ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(),
                    CharsetUtil.UTF_8);
            res.content().writeBytes(buf);
            buf.release();
        }
        ChannelFuture f = ctx.channel().writeAndFlush(res);
        // 如果是非Keep-Alive，关闭连接
        if (!isKeepAlive(req) || res.status().code() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        log.info("会话出现异常", cause);
    }

}
